/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus

This file is part of Tremulous.

Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
 */

#include "g_local.h"

// NULL for everyone

void QDECL PrintMsg(gentity_t *ent, const char *fmt, ...) {
  char msg[ 1024 ];
  va_list argptr;
  char *p;

  va_start(argptr, fmt);

  if (vsprintf(msg, fmt, argptr) > sizeof ( msg))
    G_Error("PrintMsg overrun");

  va_end(argptr);

  // double quotes are bad
  while ((p = strchr(msg, '"')) != NULL)
    *p = '\'';

  trap_SendServerCommand(((ent == NULL) ? -1 : ent - g_entities), va("print \"%s\"", msg));
}

/*
==============
OnSameTeam
==============
 */
qboolean OnSameTeam(gentity_t *ent1, gentity_t *ent2) {
  if (!ent1->client || !ent2->client)
    return qfalse;

  if (ent1->client->pers.teamSelection == ent2->client->pers.teamSelection)
    return qtrue;

  return qfalse;
}

/*
===========
Team_GetLocation

Report a location for the player. Uses placed nearby target_location entities
============
 */
gentity_t *Team_GetLocation(gentity_t *ent) {
  gentity_t *eloc, *best;
  float bestlen, len;
  vec3_t origin;

  best = NULL;
  bestlen = 3.0f * 8192.0f * 8192.0f;

  VectorCopy(ent->r.currentOrigin, origin);

  for (eloc = level.locationHead; eloc; eloc = eloc->nextTrain) {
    len = (origin[ 0 ] - eloc->r.currentOrigin[ 0 ]) * (origin[ 0 ] - eloc->r.currentOrigin[ 0 ])
            + (origin[ 1 ] - eloc->r.currentOrigin[ 1 ]) * (origin[ 1 ] - eloc->r.currentOrigin[ 1 ])
            + (origin[ 2 ] - eloc->r.currentOrigin[ 2 ]) * (origin[ 2 ] - eloc->r.currentOrigin[ 2 ]);

    if (len > bestlen)
      continue;

    if (!trap_InPVS(origin, eloc->r.currentOrigin))
      continue;

    bestlen = len;
    best = eloc;
  }

  return best;
}

/*
===========
Team_GetLocationMsg

Report a location message for the player. Uses placed nearby target_location entities
============
 */
qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen) {
  gentity_t *best;

  best = Team_GetLocation(ent);

  if (!best)
    return qfalse;

  if (best->count) {
    if (best->count < 0)
      best->count = 0;

    if (best->count > 7)
      best->count = 7;

    Com_sprintf(loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message);
  } else
    Com_sprintf(loc, loclen, "%s", best->message);

  return qtrue;
}

/*---------------------------------------------------------------------------*/

static int QDECL SortClients(const void *a, const void *b) {
  return *(int *) a - *(int *) b;
}

/*
==================
TeamplayLocationsMessage

Format:
  clientNum location health armor weapon powerups

==================
 */
void TeamplayInfoMessage(gentity_t *ent) {
  char entry[ 1024 ];
  char string[ 8192 ];
  int stringlength;
  int i, j;
  gentity_t *player;
  int cnt;
  int h;
  int clients[ TEAM_MAXOVERLAY ];

  if (!ent->client->pers.teamInfo)
    return;
  if(ent->r.svFlags & SVF_BOT)
    return;

  for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
    player = g_entities + level.sortedClients[ i ];

    if (player->inuse && player->client->sess.sessionTeam ==
            ent->client->sess.sessionTeam)
      clients[ cnt++ ] = level.sortedClients[ i ];
  }

  // We have the top eight players, sort them by clientNum
  qsort(clients, cnt, sizeof ( clients[ 0 ]), SortClients);

  // send the latest information on all clients
  string[ 0 ] = 0;
  stringlength = 0;

  for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
    player = g_entities + i;

    if (player->inuse && player->client->sess.sessionTeam ==
            ent->client->sess.sessionTeam) {
      h = player->client->ps.stats[ STAT_HEALTH ];

      if (h < 0)
        h = 0;

      Com_sprintf(entry, sizeof ( entry),
              " %i %i %i %i",
              //        level.sortedClients[i], h, a,
              i, h,
              player->client->ps.weapon, player->s.powerups);

      j = strlen(entry);

      if (stringlength + j > sizeof ( string))
        break;

      strcpy(string + stringlength, entry);
      stringlength += j;
      cnt++;
    }
  }

  trap_SendServerCommand(ent - g_entities, va("tinfo %i %s", cnt, string));
}

void CheckTeamStatus(void) {
  int i;
  gentity_t *loc, *ent;

  if (level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME) {
    level.lastTeamLocationTime = level.time;

    for (i = 0; i < g_maxclients.integer; i++) {
      ent = g_entities + i;
      if (ent->client->pers.connected != CON_CONNECTED)
        continue;

      if (ent->inuse && (ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ||
              ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS)) {

        loc = Team_GetLocation(ent);

        if (loc)
          ent->client->pers.teamState.location = loc->health;
        else
          ent->client->pers.teamState.location = 0;
      }
    }

    for (i = 0; i < g_maxclients.integer; i++) {
      ent = g_entities + i;
      if (ent->client->pers.connected != CON_CONNECTED)
        continue;

      if (ent->inuse && (ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ||
              ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS))
        TeamplayInfoMessage(ent);
    }
  }

  //Warn on unbalanced teams
  if (g_teamImbalanceWarnings.integer && !level.intermissiontime && level.time - level.lastTeamUnbalancedTime > (g_teamImbalanceWarnings.integer * 1000) && level.numTeamWarnings < 3) {
    level.lastTeamUnbalancedTime = level.time;
    if (level.numAlienSpawns > 0 && level.numHumanClients - level.numAlienClients > 2) {
      //trap_SendServerCommand (-1, "print \"Teams are unbalanced. Humans have more players.\n Humans will keep their points when switching teams.\n\"");
      level.numTeamWarnings++;
    } else if (level.numHumanSpawns > 0 && level.numAlienClients - level.numHumanClients > 2) {
      //trap_SendServerCommand (-1, "print \"Teams are unbalanced. Aliens have more players.\n Aliens will keep their points when switching teams.\n\"");
      level.numTeamWarnings++;
    } else {
      level.numTeamWarnings = 0;
    }
  }
}
